using System;
using System.Collections.Generic;
using System.Text;
using SharpMud.MudLib.Common.Environment;
using SharpMud.MudLib.Common.Environment.Persistance;
using SharpMud.MudLib.NovaSMAUG.Interop;
using SharpMud.MudLib.NovaSMAUG.Interop.IO;

namespace SharpMud.MudLib.NovaSMAUG.Environment.Persistance.Legacy
{
    public class AreaStreamer : IAreaStreamer<AreaInstance>
    {
        #region IAreaStreamer<AreaInstance> Members

        IAreaLoadResults<AreaInstance> IAreaStreamer<AreaInstance>.LoadArea(System.IO.Stream stream)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        IAreaSaveResults IAreaStreamer<AreaInstance>.SaveArea(System.IO.Stream stream, AreaInstance area)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion

        public static AreaLoadResults load_area_file(string filename)
        {
            System.IO.Stream fpArea;
            AreaLoadResults tarea = new AreaLoadResults();
            tarea.LoadedAreaDefinition = new AreaDefinition();

            try
            {
                fpArea = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
            }
            catch (System.IO.FileNotFoundException e)
            {
                tarea.AddMessage("File not found!", filename, true);
                return tarea;
            }
            catch (System.Exception e)
            {
                tarea.AddMessage(AreaLoadMessage.FromException(e));
                return tarea;
            }
            if (fpArea == null)
            {
                tarea.AddMessage("Error loading file!", filename, true);
                return tarea;
            }
            tarea.area_version = 0;
            for (; ; )
            {
                char[] word;
                Interop.ArrayIndexPointer<char> pword;

                if (Interop.IO.Stream.fread_letter(fpArea) != '#')
                {
                    Interop.IO.Debug.bug(tarea.FileName);
                    Interop.IO.Debug.bug("{0}: # not found", Interop.IO.Debug.getThisMethod().Name);
                    return tarea;
                }

                word = Interop.IO.Stream.fread_word(fpArea).ToCharArray();
                pword = Interop.ArrayIndexPointer<char>.Create(word);

                if (word[0] == '$') break;
                else if (!Interop.Text.str_cmp(word, "AREA"))
                {
                    tarea.LoadedAreaDefinition.Header.name = Interop.IO.Stream.fread_string_nohash(fpArea);
                }
                else if (!Interop.Text.str_cmp(word, "AUTHOR")) load_author(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "FLAGS")) load_flags(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "RANGES")) load_ranges(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "ECONOMY")) load_economy(tarea, fpArea);
#if ENABLE_OVERLAND
                else if (!Interop.Text.str_cmp(word, "CONTINENT")) load_continent(tarea, fpArea);
#endif
                else if (!Interop.Text.str_cmp(word, "RESETMSG")) load_resetmsg(tarea, fpArea);
                /* Rennard */
                else if (!Interop.Text.str_cmp(word, "HELPS")) load_helps(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "MOBILES")) load_mobiles(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "MUDPROGS")) load_mudprogs(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "OBJECTS")) load_objects(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "OBJPROGS")) load_objprogs(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "RESETS")) load_resets(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "ROOMS")) load_rooms(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "SHOPS")) load_shops(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "REPAIRS")) load_repairs(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "SPECIALS")) load_specials(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "CLIMATE")) load_climate(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "NEIGHBOR")) load_neighbor(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "VERSION")) load_version(tarea, fpArea);
                else if (!Interop.Text.str_cmp(word, "SPELLLIMIT"))
                {
                    tarea.LoadedAreaDefinition.Header.spelllimit = Interop.IO.Stream.fread_number(fpArea);
                }
                else
                {
                    tarea.AddMessage("Bad section name \"#" + word + "\"!", tarea.FileName, true);
                    return tarea;
                }
            }
            fpArea.Close();
            fpArea = null;

            return tarea;
        }

        #region Load # Sections

        private static void load_version(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_neighbor(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_climate(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_specials(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_repairs(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_shops(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_rooms(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_resets(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_objprogs(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_objects(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_mudprogs(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void load_mobiles(AreaLoadResults tarea, System.IO.Stream fp)
        {
	MOB_INDEX_DATA *pMobIndex;
	char *ln;
	int x1, x2, x3, x4, x5, x6, x7, x8;

	if ( !tarea )
	{
		bug( "Load_mobiles: no #AREA seen yet." );
		if ( fBootDb )
		{
			shutdown_mud( "No #AREA" );
			exit( 1 );
		}
		else
			return;
	}

	for ( ; ; )
	{
		char buf[MAX_STRING_LENGTH];
		sh_int vnum;
		char letter;
		int iHash;
		bool oldmob;
		bool tmpBootDb;

		letter				= fread_letter( fp );
		if ( letter != '#' )
		{
			bug( "Load_mobiles: # not found." );
			if ( fBootDb )
			{
				shutdown_mud( "# not found" );
				exit( 1 );
			}
			else
				return;
		}

		vnum				= fread_number( fp );
		if ( vnum == 0 )
			break;

		tmpBootDb = fBootDb;
		fBootDb = FALSE;
		if ( get_mob_index( vnum ) )
		{
			if ( tmpBootDb )
			{
				bug( "Load_mobiles: vnum %d duplicated.", vnum );
				shutdown_mud( "duplicate vnum" );
				exit( 1 );
			}
			else
			{
				pMobIndex = get_mob_index( vnum );
				sprintf( buf, "Cleaning mobile: %d", vnum );
				log_string_plus( buf, LOG_BUILD, sysdata.log_level );
				clean_mob( pMobIndex );
				oldmob = TRUE;
			}
		}
		else
		{
			oldmob = FALSE;
			CREATE( pMobIndex, MOB_INDEX_DATA, 1 );
		}
		fBootDb = tmpBootDb;

		pMobIndex->vnum			= vnum;
		if ( fBootDb )
		{
			if ( !tarea->low_m_vnum )
				tarea->low_m_vnum	= vnum;
			if ( vnum > tarea->hi_m_vnum )
				tarea->hi_m_vnum	= vnum;
		}
		pMobIndex->player_name		= fread_string( fp );
		pMobIndex->short_descr		= fread_string( fp );
		pMobIndex->long_descr		= fread_string( fp );
		pMobIndex->description		= fread_string( fp );

		pMobIndex->long_descr[0]	= UPPER(pMobIndex->long_descr[0]);
		pMobIndex->description[0]	= UPPER(pMobIndex->description[0]);

		pMobIndex->act			= fread_bitvector( fp );
		xSET_BIT(pMobIndex->act, ACT_IS_NPC);
		pMobIndex->affected_by		= fread_bitvector( fp );
		pMobIndex->pShop		= NULL;
		pMobIndex->rShop		= NULL;
		pMobIndex->alignment		= fread_number( fp );
		letter				= fread_letter( fp );
		pMobIndex->level		= fread_number( fp );

		pMobIndex->mobthac0		= fread_number( fp );
		pMobIndex->ac			= fread_number( fp );
		pMobIndex->hitnodice		= fread_number( fp );
		/* 'd'		*/		  fread_letter( fp );
		pMobIndex->hitsizedice		= fread_number( fp );
		/* '+'		*/		  fread_letter( fp );
		pMobIndex->hitplus		= fread_number( fp );
		pMobIndex->damnodice		= fread_number( fp );
		/* 'd'		*/		  fread_letter( fp );
		pMobIndex->damsizedice		= fread_number( fp );
		/* '+'		*/		  fread_letter( fp );
		pMobIndex->damplus		= fread_number( fp );
		pMobIndex->gold			= fread_number( fp );
		pMobIndex->exp			= fread_number( fp );

		/* pMobIndex->position		= fread_number( fp ); */
		pMobIndex->position          = fread_number( fp );
		if(pMobIndex->position<100){
			switch(pMobIndex->position){
				default: 
				case 0: 
				case 1: 
				case 2: 
				case 3: 
				case 4: break;
				case 5: pMobIndex->position=6; break;
				case 6: pMobIndex->position=8; break;
				case 7: pMobIndex->position=9; break;
				case 8: pMobIndex->position=12; break;
				case 9: pMobIndex->position=13; break;
				case 10: pMobIndex->position=14; break;
				case 11: pMobIndex->position=15; break;
			}
		} else {
			pMobIndex->position-=100;
		}

		/* pMobIndex->defposition		= fread_number( fp ); */
		pMobIndex->defposition          = fread_number( fp );
		if(pMobIndex->defposition<100){
			switch(pMobIndex->defposition){
				default: 
				case 0: 
				case 1: 
				case 2: 
				case 3: 
				case 4: break;
				case 5: pMobIndex->defposition=6; break;
				case 6: pMobIndex->defposition=8; break;
				case 7: pMobIndex->defposition=9; break;
				case 8: pMobIndex->defposition=12; break;
				case 9: pMobIndex->defposition=13; break;
				case 10: pMobIndex->defposition=14; break;
				case 11: pMobIndex->defposition=15; break;
			}
		} else {
			pMobIndex->defposition-=100;
		}


		/*
		* Back to meaningful values.
		*/
		pMobIndex->sex			= fread_number( fp );

		if ( letter != 'S' && letter != 'C' )
		{
			bug( "Load_mobiles: vnum %d: letter '%c' not S or C.", vnum,
				letter );
			shutdown_mud( "bad mob data" );
			exit( 1 );
		}
		if ( letter == 'C' ) /* Realms complex mob 	-Thoric */
		{
			pMobIndex->perm_str			= fread_number( fp );
			pMobIndex->perm_int			= fread_number( fp );
			pMobIndex->perm_wis			= fread_number( fp );
			pMobIndex->perm_dex			= fread_number( fp );
			pMobIndex->perm_con			= fread_number( fp );
			pMobIndex->perm_cha			= fread_number( fp );
			pMobIndex->perm_lck			= fread_number( fp );
			pMobIndex->saving_poison_death	= fread_number( fp );
			pMobIndex->saving_wand		= fread_number( fp );
			pMobIndex->saving_para_petri	= fread_number( fp );
			pMobIndex->saving_breath		= fread_number( fp );
			pMobIndex->saving_spell_staff	= fread_number( fp );
			ln = fread_line( fp );
			x1=x2=x3=x4=x5=x6=x7=x8=0;
			sscanf( ln, "%d %d %d %d %d %d %d",
				&x1, &x2, &x3, &x4, &x5, &x6, &x7 );
			pMobIndex->race		= x1;
			pMobIndex->class		= x2;
			pMobIndex->height		= x3;
			pMobIndex->weight		= x4;
			pMobIndex->speaks		= x5;
			pMobIndex->speaking		= x6;
			pMobIndex->numattacks	= x7;
			/*  Thanks to Nick Gammon for noticing this.
			if ( !pMobIndex->speaks )
			pMobIndex->speaks = race_table[pMobIndex->race]->language | LANG_COMMON;
			if ( !pMobIndex->speaking )
			pMobIndex->speaking = race_table[pMobIndex->race]->language;
			*/
			if ( !pMobIndex->speaks )
				pMobIndex->speaks = LANG_COMMON;
			if ( !pMobIndex->speaking )
				pMobIndex->speaking = LANG_COMMON;

#if !XBI
			ln = fread_line( fp );
			x1=x2=x3=x4=x5=x6=x7=x8=0;
			sscanf( ln, "%d %d %d %d %d %d %d %d",
				&x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8 );
			pMobIndex->hitroll		= x1;
			pMobIndex->damroll		= x2;
			pMobIndex->xflags		= x3;
			pMobIndex->resistant	= x4;
			pMobIndex->immune		= x5;
			pMobIndex->susceptible	= x6;
			pMobIndex->attacks		= x7;
			pMobIndex->defenses		= x8;
#else
			pMobIndex->hitroll		= fread_number(fp);
			pMobIndex->damroll		= fread_number(fp);
			pMobIndex->xflags		= fread_number(fp);
			pMobIndex->resistant	= fread_number(fp);
			pMobIndex->immune		= fread_number(fp);
			pMobIndex->susceptible	= fread_number(fp);
			pMobIndex->attacks		= fread_bitvector(fp);
			pMobIndex->defenses		= fread_bitvector(fp);
#endif
		}
		else
		{
			pMobIndex->perm_str		= 13;
			pMobIndex->perm_dex		= 13;
			pMobIndex->perm_int		= 13;
			pMobIndex->perm_wis		= 13;
			pMobIndex->perm_cha		= 13;
			pMobIndex->perm_con		= 13;
			pMobIndex->perm_lck		= 13;
			pMobIndex->race		= 0;
			pMobIndex->class		= 3;
			pMobIndex->xflags		= 0;
			pMobIndex->resistant	= 0;
			pMobIndex->immune		= 0;
			pMobIndex->susceptible	= 0;
			pMobIndex->numattacks	= 0;
#if XBI
			xCLEAR_BITS(pMobIndex->attacks);
			xCLEAR_BITS(pMobIndex->defenses);
#else
			pMobIndex->attacks		= 0;
			pMobIndex->defenses		= 0;
#endif
		}

		letter = fread_letter( fp );
		if ( letter == '>' )
		{
			ungetc( letter, fp );
			mprog_read_programs( fp, pMobIndex );
		}
		else ungetc( letter,fp );

		if ( !oldmob )
		{
			iHash			= vnum % MAX_KEY_HASH;
			pMobIndex->next		= mob_index_hash[iHash];
			mob_index_hash[iHash]	= pMobIndex;
			top_mob_index++;
		}
	}

	return;
        }

        /// <summary>
        /// Load a help section
        /// </summary>
        private static void load_helps(AreaLoadResults tarea, System.IO.Stream fp)
        {
            HelpData pHelp;

            for (; ; )
            {
                pHelp = new HelpData();
                pHelp.level = (short)Stream.fread_number(fp);
                pHelp.keyword = Stream.fread_string(fp);
                if (pHelp.keyword==null || pHelp.keyword.Length == 0)
                {
                    pHelp = null;
                    continue;
                }
                if (pHelp.keyword[0] == '$')
                {
                    pHelp = null;
                    break;
                }
                pHelp.text = Stream.fread_string(fp);
                tarea.LoadedAreaDefinition.Helps.Add(pHelp);
            }
        }

        /// <summary>
        /// Reset Message Load
        /// </summary>
        /// <credits>Rennard</credits>
        private static void load_resetmsg(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            tarea.LoadedAreaDefinition.Header.resetmsg = Stream.fread_string_nohash(fpArea);
        }

        /// <summary>
        /// Load a continent reference
        /// </summary>
        /// <credits>Samson (9-16-00)</credits>
        private static void load_continent(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            tarea.LoadedAreaDefinition.Header.continent = new ContinentReference(Stream.fread_string(fpArea), -1);
        }

        /// <summary>
        /// Load an economy section
        /// </summary>
        /// <credits>Thoric</credits>
        private static void load_economy(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            tarea.LoadedAreaDefinition.Header.economy.high = Stream.fread_number(fpArea);
            tarea.LoadedAreaDefinition.Header.economy.low = Stream.fread_number(fpArea);
            return;
        }

        private static void load_ranges(AreaLoadResults tarea, System.IO.Stream fp)
        {
            List<int> x = new List<int>();
            string ln;
            string[] ln_a;

            for (; ; )
            {
                ln = Stream.fread_line(fp);
                if (ln[0] == '$')
                    break;
                while (ln.IndexOf("  ") >= 0)
                    ln.Replace(   "  ", " ");

                ln_a = ln.Split(' ', '\t');
                foreach (string s in ln_a)
                {
                    bool sx;
                    int y;
                    sx = int.TryParse(s,out y);
                    if(sx)
                        x.Add(y);
                }

                if(x.Count>=1)
                    tarea.LoadedAreaDefinition.Header.LevelRecommendationRange.low = x[0];
                if(x.Count>=2)
                    tarea.LoadedAreaDefinition.Header.LevelRecommendationRange.high = x[1];
                if (x.Count >= 3)
                    tarea.LoadedAreaDefinition.Header.LevelRestrictionRange.low = x[2];
                if (x.Count >= 4)
                    tarea.LoadedAreaDefinition.Header.LevelRestrictionRange.high = x[3];
            }
        }

        private static void load_flags(AreaLoadResults tarea, System.IO.Stream fp)
        {
            string ln;
            ln = Stream.fread_line(fp).Trim();

            string ln1 = ln.Split(' ', '\t')[0].Trim();
            string ln2 = ln.Substring(ln.IndexOfAny(new char[] { ' ', '\t' })).Trim();
            
            int x1 = int.Parse(ln1), x2 = int.Parse(ln2);
            tarea.LoadedAreaDefinition.Header.flags = x1;
            if (x2 > 0)
            {
                tarea.LoadedAreaDefinition.Header.reset_frequency = (short)x2;
                tarea.LoadedAreaDefinition.Header.age = (short)x2;
            }
            return;
        }

        private static void load_author(AreaLoadResults tarea, System.IO.Stream fpArea)
        {
            tarea.LoadedAreaDefinition.Header.author = Stream.fread_string(fpArea);
        }
        #endregion
    }
}
